#include "src/net/event_loop_thread.h"

#include "src/net/event_loop.h"

namespace fio66::net
{
  EventLoopThread::EventLoopThread(const ThreadInitCallback& cb,
                                 const std::string& name)
  : name_(name),
    loop_(NULL),
    exiting_(false),
    thread_(),
    mutex_(),
    cond_(),
    callback_(cb)
{
}

EventLoopThread::~EventLoopThread()
{
  exiting_ = true;
  if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_.
  {
    // still a tiny chance to call destructed object, if threadFunc exits just now.
    // but when EventLoopThread destructs, usually programming is exiting anyway.
    loop_->Quit();
    thread_.join();
  }
}

EventLoop* EventLoopThread::StartLoop()
{
  thread_ = std::jthread(std::bind(&EventLoopThread::ThreadFunc, this));

  EventLoop* loop = NULL;
  {
    std::unique_lock lock(mutex_);
    while (loop_ == NULL)
    {
      cond_.wait(lock);
    }
    loop = loop_;
  }

  return loop;
}

void EventLoopThread::ThreadFunc()
{
  EventLoop loop;

  if (callback_)
  {
    callback_(&loop);
  }

  {
    std::unique_lock lock(mutex_);
    loop_ = &loop;
    cond_.notify_one();
  }

  loop.Loop();
  //assert(exiting_);
  std::unique_lock lock(mutex_);
  loop_ = NULL;
}
} // namespace fio66::net
